/**
 * 
 */
package com.vision.sales.cm.db.data;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import net.sf.gilead.pojo.gwt.LightEntity;

import com.vision.core.cm.db.data.Company;


/**
 * @author Mark
 *
 */
@Entity
@Table(name = CollectionItem.TABLE)
public class CollectionItem extends LightEntity implements Serializable {
	
	private static final long serialVersionUID = 9205486819775548192L;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public static final String TABLE = "collection_item";
	
	public static final String COL_ID = "id";
	public static final String COL_COMPANY_ID = "company_id";
	public static final String COL_COLLECTION_ID = "collection_id";
	public static final String COL_INVOICE_ID = "invoice_id";
	public static final String COL_CUSTOMER_ID = "customer_id";
	public static final String COL_DATE = "date";
	
	public static final String COL_AMOUNT = "amount";
	public static final String COL_OVERRUNS = "overruns";
	public static final String COL_OVERPAYMENTS = "overpayments";
	public static final String COL_DISCOUNTS = "discounts";
	public static final String COL_REJECTS = "rejects";
	public static final String COL_RETURNS = "returns";
	
	public static final String COL_SUBTOTAL = "subtotal";
	public static final String COL_TAX = "tax";
	public static final String COL_NET_AMOUNT = "net_amount";
	
	public static final String COL_TAX_OVERRIDDEN = "tax_overridden";
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	/**
	 * Tax divisor constant. Value = 112.
	 */
	public static final double TAX_DIVISOR = 112D;
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "scollection_item")
	@SequenceGenerator(name = "scollection_item", sequenceName = "collection_item_seq")
	@Column(name = COL_ID)
	private Long id;
	
	@ManyToOne
	@JoinColumn(name = COL_COMPANY_ID, nullable = false)
	private Company company;

	@Id
	@ManyToOne
	@JoinColumn(name = COL_COLLECTION_ID, nullable = false)
	private Collection collection;

	@Id
	@ManyToOne
	@JoinColumn(name = COL_INVOICE_ID, nullable = false)
	private SalesInvoice salesInvoice;
	
	/**
	 * Same as the date from {@link #collection}.
	 */
	@Column(name = COL_DATE, nullable = false)
	@Temporal(TemporalType.DATE)
	private Date date;
	
	/**
	 * Same as the {@link Customer} from {@link #salesInvoice}.
	 */
	@ManyToOne
	@JoinColumn(name = COL_CUSTOMER_ID, nullable = false)
	private Customer customer;
	
	@Column(name = COL_AMOUNT, nullable = false)
	private double amount;
	
	// From DebitMemo
	@Column(name = COL_OVERRUNS)
	private Double overruns;
	
	@Column(name = COL_OVERPAYMENTS)
	private Double overpayments;
	
	// From CreditMemo
	@Column(name = COL_DISCOUNTS)
	private Double discounts;
	
	@Column(name = COL_REJECTS)
	private Double rejects;
	
	@Column(name = COL_RETURNS)
	private Double returns;
	
	/**
	 * Computed as:
	 * <p>
	 * 	{@link #amount} - {@link #overruns} + {@link #overpayments} - ({@link #discounts} + {@link #rejects} + {@link #returns} + {@link #badDebts})
	 * </p>
	 */
	@Column(name = COL_SUBTOTAL, nullable = false)
	private double subtotal;
	
	@Column(name = COL_TAX, nullable = false)
	private double tax;
	
	/**
	 * Computed as:
	 * <p>
	 * 	{@link #subtotal} - {@link #tax}
	 * </p>
	 */
	@Column(name = COL_NET_AMOUNT, nullable = false)
	private double netAmount;
	
	// Field used to indicate if the automcatically computed tax was overridden
	@Column(name = COL_TAX_OVERRIDDEN, nullable = false)
	private boolean taxOverridden = false;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Override
	public boolean equals(Object o) {
		if (o instanceof CollectionItem) {
			CollectionItem ci = (CollectionItem) o;
			return id != null && id.equals(ci.id);
		}
		
		return false;
	}
	
	@Override
	public int hashCode() {
		return id == null ? super.hashCode() : id.hashCode();
	}
	
	@Override
	public String toString() {
		return getCompany().getId() + ": " + getCollection().getId() + ": " + getSalesInvoice().getId(); 
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	private static double safe(Double value) {
		return value == null ? 0.0D : value;
	}
	
	public void recompute() {
		setSubtotal(safe(amount) + safe(overruns) + safe(overpayments) - safe(discounts) - safe(rejects) - safe(returns));
		
		if (salesInvoice != null) {
			// If taxRate is set manually by the user, no need to recompute tax
			if (!isTaxOverridden()) {
				double taxRate = salesInvoice.getCustomer().getTaxRate();
				taxRate = taxRate / 100D; // NOTE taxRate is not saved as percent, so we divide by 100
				
				boolean isDirect = salesInvoice.getCustomer().isTaxRateDirect();
				setTax(isDirect ? (subtotal * taxRate) : (subtotal / TAX_DIVISOR * taxRate));
			}
		}
		
		setNetAmount(safe(subtotal) - safe(tax));
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
	
	public Company getCompany() {
		return company;
	}
	
	public void setCompany(Company company) {
		this.company = company;
	}
	
	public Collection getCollection() {
		return collection;
	}
	
	public void setCollection(Collection collection) {
		this.collection = collection;
	}

	public SalesInvoice getSalesInvoice() {
		return salesInvoice;
	}

	public void setSalesInvoice(SalesInvoice salesInvoice) {
		this.salesInvoice = salesInvoice;
	}
	
	public Long getSalesInvoiceId() {
		return getSalesInvoice().getId();
	}
	
	public Customer getCustomer() {
		return customer;
	}
	
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
	
	public Date getDate() {
		return date;
	}
	
	public void setDate(Date date) {
		this.date = date;
	}

	public double getAmount() {
		return amount;
	}

	public void setAmount(double amount) {
		this.amount = amount;
		recompute();
	}

	public Double getOverruns() {
		return overruns;
	}

	public void setOverruns(Double overruns) {
		this.overruns = overruns;
		recompute();
	}
	
	public Double getOverpayments() {
		return overpayments;
	}
	
	public void setOverpayments(Double overpayments) {
		this.overpayments = overpayments;
		recompute();
	}

	public Double getDiscounts() {
		return discounts;
	}

	public void setDiscounts(Double discounts) {
		this.discounts = discounts;
		recompute();
	}

	public Double getRejects() {
		return rejects;
	}

	public void setRejects(Double rejects) {
		this.rejects = rejects;
		recompute();
	}

	public Double getReturns() {
		return returns;
	}

	public void setReturns(Double returns) {
		this.returns = returns;
		recompute();
	}

	public double getSubtotal() {
		return subtotal;
	}

	public void setSubtotal(double subtotal) {
		this.subtotal = subtotal;
	}

	public double getTax() {
		return tax;
	}

	public void setTax(double tax) {
		this.tax = tax;
	}

	public double getNetAmount() {
		return netAmount;
	}

	public void setNetAmount(double netAmount) {
		this.netAmount = netAmount;
	}
	
	public boolean isTaxOverridden() {
		return taxOverridden;
	}
	
	public void setTaxOverridden(boolean taxOverridden) {
		this.taxOverridden = taxOverridden;
	}

}
